-
-
Notifications
You must be signed in to change notification settings - Fork 547
Add Multi-Channel Measurement Querying REST API #1472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: kizniche <[email protected]>
Co-authored-by: kizniche <[email protected]>
Co-authored-by: kizniche <[email protected]>
Co-authored-by: kizniche <[email protected]>
Co-authored-by: kizniche <[email protected]>
Co-authored-by: kizniche <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a new REST API endpoint for querying multiple sensor measurement channels in a single HTTP request, addressing the need to reduce network overhead for mobile clients working with multi-channel sensors.
- Adds
POST /api/measurements/multiendpoint that accepts multiple channel specifications and returns all measurements in one response - Implements
read_influxdb_multi()function to efficiently query multiple channels by reusing existing single-channel logic - Provides comprehensive documentation, testing, and maintains 100% backward compatibility
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| mycodo/utils/influx.py | Core multi-channel query function that aggregates results from multiple single-channel queries |
| mycodo/mycodo_flask/api/measurement.py | REST API endpoint with authentication, validation, and response formatting |
| mycodo/tests/software_tests/test_influxdb/test_influxdb.py | Unit test for multi-channel functionality |
| docs/Multi-Channel-API-*.md | Comprehensive documentation including usage guide, testing procedures, implementation details, and architecture diagrams |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
|
||
| example: | ||
| channels_data = [ | ||
| {'unique_id': '00000001', 'unit': 'C', 'channel': 0, 'measure': 'temperature'}, | ||
| {'unique_id': '00000001', 'unit': '%', 'channel': 1, 'measure': 'humidity'} | ||
| ] | ||
| read_influxdb_multi(channels_data, past_seconds=3600) | ||
|
|
||
| :return: dict mapping channel index to [time, value] | ||
| :rtype: dict | ||
|
|
Copilot
AI
Oct 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function docstring should include return type documentation for the dictionary structure. It currently states "dict mapping channel index to [time, value]" but doesn't specify that the keys are integers (0-based indices) and values are lists with two elements.
| example: | |
| channels_data = [ | |
| {'unique_id': '00000001', 'unit': 'C', 'channel': 0, 'measure': 'temperature'}, | |
| {'unique_id': '00000001', 'unit': '%', 'channel': 1, 'measure': 'humidity'} | |
| ] | |
| read_influxdb_multi(channels_data, past_seconds=3600) | |
| :return: dict mapping channel index to [time, value] | |
| :rtype: dict | |
| example: | |
| channels_data = [ | |
| {'unique_id': '00000001', 'unit': 'C', 'channel': 0, 'measure': 'temperature'}, | |
| {'unique_id': '00000001', 'unit': '%', 'channel': 1, 'measure': 'humidity'} | |
| ] | |
| read_influxdb_multi(channels_data, past_seconds=3600) | |
| :return: Dictionary mapping integer channel indices (0-based) to a list [time, value], where | |
| time is a float (timestamp) or datetime object, and value is the measurement value. | |
| :rtype: dict[int, list[time, value]] |
| if channel is None: | ||
| abort(422, custom=f'channel is required for channel at index {idx}') | ||
|
|
||
| if unit not in add_custom_units(Unit.query.all()): |
Copilot
AI
Oct 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The add_custom_units(Unit.query.all()) call is executed inside a loop for each channel validation. This database query should be moved outside the loop to avoid N database queries for N channels.
| from mycodo.utils.influx import (add_measurements_influxdb, read_influxdb_multi, | ||
| read_influxdb_single) |
Copilot
AI
Oct 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The import statement spans multiple lines but could be formatted more consistently with the existing single-line import style in the same file.
| from mycodo.utils.influx import (add_measurements_influxdb, read_influxdb_multi, | |
| read_influxdb_single) | |
| from mycodo.utils.influx import add_measurements_influxdb, read_influxdb_multi, read_influxdb_single |
|
@cajun1689 If you could test and let me know if this works to your liking, I'll merge it. Thanks. |
Overview
This PR implements a new REST API endpoint for querying multiple sensor measurement channels in a single HTTP request, addressing the feature request to reduce network overhead for mobile clients working with multi-channel sensors like BME680, BME688, and Atlas Scientific multi-probes.
Problem
Mobile clients previously had to make N separate API calls to query N sensor channels, resulting in:
For example, querying a 4-channel BME680 sensor (temperature, humidity, pressure, gas) required 4 separate HTTP requests, taking ~240ms with typical network latency.
Solution
New REST Endpoint:
POST /api/measurements/multiAccepts multiple channel specifications in a single request and returns all measurements in one response:
Response:
{ "measurements": [ {"unique_id": "bme680_001", "unit": "C", "channel": 0, "time": 1703894523.456, "value": 25.5}, {"unique_id": "bme680_001", "unit": "%", "channel": 1, "time": 1703894523.456, "value": 65.3}, {"unique_id": "bme680_001", "unit": "hPa", "channel": 2, "time": 1703894523.456, "value": 1013.2} ] }Implementation Details
Core Function:
read_influxdb_multi()mycodo/utils/influx.pyread_influxdb_single()functionREST API Endpoint:
MeasurementsMultimycodo/mycodo_flask/api/measurement.pyAPI Models
Performance Impact
Example: 4-channel BME680 sensor with 50ms network latency
Testing
test_influxdb_multi()unit test to validate multi-channel queryingDocumentation
Added extensive documentation in
docs/directory:Backward Compatibility
✅ 100% backward compatible
Security
@flask_login.login_required)Deployment
Zero-risk deployment - simply deploy code and restart Flask:
Endpoint immediately available at
/api/measurements/multi. Rollback is safe as new endpoint is completely isolated.WebSocket Support
WebSocket support is not included in this PR (intentionally):
Files Changed
mycodo/utils/influx.py(+59 lines) - Core multi-channel query functionmycodo/mycodo_flask/api/measurement.py(+129 lines) - REST API endpointmycodo/tests/software_tests/test_influxdb/test_influxdb.py(+52 lines) - Unit testsdocs/(+1,413 lines) - Comprehensive documentation (5 new files)Total: 8 files, 1,705 lines added
Design Decisions
Iterative queries: Reuses
read_influxdb_single()for each channel rather than complex batched queriesPOST method: Uses POST with JSON body instead of GET
This implementation provides immediate value to mobile clients with minimal code changes, comprehensive documentation, and zero deployment risk.
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.